/*
#Copyright (c) 2013, Philippe Bordron <philippe.bordron@gmail.com>
#
# This file is part of SIPPER.
#
# DCC is free software: you can redistribute it and/or modify
# it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# DCC is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU LESSER GENERAL PUBLIC LICENSE for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# along with SIPPER.  If not, see <http://www.gnu.org/licenses/>
*/
package combi.wip.sipper.exec;

import combi.sipper.io.IODistanceMatrix;
import combi.sipper.io.IOSimpleGraph;
import combi.sipper.io.InFlatFile;
import combi.wip.sipper.io.IOGenome;
import combi.wip.sipper.io.IOMetabolicNetworkWithEnzymes;
import combi.wip.sipper.io.IObioASP;
import combi.wip.sipper.io.Profil;
import combi.sipper.modeling.distances.DistanceBetweenGenes;
import combi.sipper.modeling.distances.DistanceCoexpression;
import combi.sipper.modeling.distances.DistanceColocalisation;
import combi.wip.sipper.modeling.reactions.ReactionUtil.Orientation;


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.transform.TransformerConfigurationException;


import org.jgrapht.DirectedGraph;
import org.jgrapht.Graph;
import org.jgrapht.UndirectedGraph;
import org.jgrapht.ext.DOTExporter;
import org.jgrapht.ext.GmlExporter;
import org.jgrapht.ext.GraphMLExporter;
import org.jgrapht.ext.IntegerEdgeNameProvider;
import org.jgrapht.ext.IntegerNameProvider;
import org.jgrapht.ext.StringNameProvider;
import org.jgrapht.graph.*;
import org.xml.sax.SAXException;

import combi.wip.sipper.io.dot.WeightedEdgeNameProvider;
import combi.wip.sipper.io.metacyc.IOGenomeFromMetaCyc;
import combi.wip.sipper.io.metacyc.IOMetabolicNetworkWithEnzymesFromMetaCyc;
import combi.wip.sipper.modeling.Protein;
import combi.wip.sipper.modeling.genomes.CircularGenome;
import combi.wip.sipper.modeling.genomes.Gene;
import combi.wip.sipper.modeling.genomes.Genome;
import combi.wip.sipper.modeling.integratedModel.GenomicModel;
import combi.wip.sipper.modeling.integratedModel.graphs.GraphGenomicModel;
import combi.wip.sipper.modeling.metabolicNetworks.ImplOfFilteredMetabolicNetworkWithEnzymes;
import combi.wip.sipper.modeling.metabolicNetworks.MetabolicNetworkUtils;
import combi.wip.sipper.modeling.metabolicNetworks.MetabolicNetworkWithEnzymes;
import combi.wip.sipper.modeling.reactions.Reaction;

//import scoresCoExp.*;
import combi.utils.Couple;
import combi.utils.Pair;
import combi.utils.Triplet;


public class CreationGintFromEcocyc {


	private static int nbParametresMin = 3;
	private static int nbParametresMax = 5;

	private static String degReactionRatioTag = "-degradation_reaction_ratio=";
	private static String distTag = "-dist=";
	private static boolean isMetricMatrix = false;
	/**
	 * @param args
	 * @throws SAXException 
	 * @throws TransformerConfigurationException 
	 */
	public static void main(String[] args) {
		// TODO Grand nettoyage

		String metricFile = null;
		float degReactionRatio = 0;
		if (args.length < nbParametresMin || args.length> nbParametresMax)
		{
			System.out.println("Incorrect parameters: parameters must be \n" +
					"ecocyc_profile_file output_repertory metabolite_cutoff\n or \n" +
					"ecocyc_profile_file output_repertory metabolite_cutoff gene_metric_file\n\n" + 
					"ecocyc_profile: see example\n\n" +
					"out_repertory: the working directory. If it not exists, it will be created\n\n" +
					"metabolite_cutoff: a integer value to remove metabolites that are present in a number of reactions strictly superior than 'metabolite_cutoff'\n\n" +
					"gene_metric_file: a NxN matrice file that give a metric between each couple of genes (Infinity is possible as a value). The file must be formated as follow\n" +
					"gene_1_id	gene_2_id	...	gene_N_id\n" +
					"val_1_1	val_1_2	... val_1_N\n" +
					"val_2_1	val_2_2	... val_2_N\n" +
					"...\n" +
					"val_N_1	val_N_2	... val_N_N");
			System.exit(1);
		}

		String profilFile = args[0];
		String outRep = args[1];
		Integer metaboliteCutOff = new Integer(args[2]);
		for (int i = 3; i < args.length; i++)
		{
			if (args[i].startsWith(degReactionRatioTag))
			{
				degReactionRatio = Float.parseFloat(args[i].substring(degReactionRatioTag.length()));
				System.err.println("Application of a degradation ration of "+ degReactionRatio + " reaction set");

			}
			if(args[i].startsWith(distTag))
			{
				metricFile = args[i].substring(distTag.length());
				isMetricMatrix = true;
			}
		}

		try {
			Profil ecocycFiles = Profil.createProfil(profilFile);

			File outputRep = new File(outRep);
			if (!outputRep.exists())
			{
				outputRep.mkdir();
			}

			BufferedWriter outLog = new BufferedWriter(new FileWriter(outRep+ "modele.log"));
			outLog.close();

			Map<String, Map<String, Collection<String>>> compounds = new HashMap<String, Map<String, Collection<String>>>();
			Map<String, Map<String, Collection<String>>> reactions = new HashMap<String, Map<String, Collection<String>>>();
			Map<String, Map<String, Collection<String>>> enzReactions = new HashMap<String, Map<String, Collection<String>>>();
			Map<String, Map<String, Collection<String>>> proteins = new HashMap<String, Map<String, Collection<String>>>();
			Map<String, Map<String, Collection<String>>> genes = new HashMap<String, Map<String, Collection<String>>>();


			// table association type avec instances du type
			Map<String,Collection<String>> typesInstances = new HashMap<String, Collection<String>>();
			Map<String, Collection<String>> componentOfComplex = new HashMap<String, Collection<String>>();
			Map<String, Collection<String>> modifiedComponents = new HashMap<String, Collection<String>>();

			// Creation du modele integre

			String componentOf = "COMPONENT-OF";
			String instanceOf = "TYPES";
			String rightPos = "RIGHT-END-POSITION";
			String leftPos = "LEFT-END-POSITION";
			String geneProduct = "PRODUCT";
			String locus = "ACCESSION-1";
			String synonyms = "SYNONYMS";


			outLog = new BufferedWriter(new FileWriter(outRep+ "modele.log", true));
			outLog.write("\nGenome Loading\n\n");
			System.err.println("\nGenome Loading");
			outLog.close();

			IOGenome<Gene<Protein>, Protein> genomeIn = new IOGenomeFromMetaCyc<Gene<Protein>>(ecocycFiles.get("ecocyc_files_path")+ ecocycFiles.get("genome"),true, ecocycFiles.get("ecocyc_files_path")+ ecocycFiles.get("proteins"));
			genomeIn.load();
			Genome<Gene<Protein>,Protein> genome = genomeIn.get();
			System.err.println(genome.size() + " genes\n"+ genome.getProductSet().size()+ " proteins");


			outLog = new BufferedWriter(new FileWriter(outRep+ "modele.log", true));
			outLog.write("Metabolic Network Loading\n\n");
			System.err.println("\nMetabolic Network Loading");
			outLog.close();

			IOMetabolicNetworkWithEnzymes<String, Reaction<String>,Protein> metaIn;
			metaIn = new IOMetabolicNetworkWithEnzymesFromMetaCyc(ecocycFiles.get("ecocyc_files_path")+ ecocycFiles.get("compounds"),
					ecocycFiles.get("ecocyc_files_path")+ ecocycFiles.get("reactions"),
					ecocycFiles.get("ecocyc_files_path")+ ecocycFiles.get("enzrxns"),
					ecocycFiles.get("ecocyc_files_path")+ ecocycFiles.get("proteins"));
			metaIn.load();

			MetabolicNetworkWithEnzymes<String, Reaction<String>, Protein> meta;
			MetabolicNetworkWithEnzymes<String, Reaction<String>, Protein> metaTemp = metaIn.get();
			
			
			int countReversibleReactions = 0;
			List<Reaction<String>> irreversibleReactions = new ArrayList<Reaction<String>>();
			for (Reaction<String> r : metaTemp.getReactionSet())
			{
				if (r.getDirection()==Orientation.BOTH || r.getDirection() == Orientation.UNDEFINED)
				{
					countReversibleReactions++;
				}
				else
				{
					irreversibleReactions.add(r);
				}
			}
			
			System.err.println(metaTemp.getCompoundSet().size() + " compounds\n"+
					metaTemp.getReactionSet().size() + " reactions : \n" +
					countReversibleReactions +" rev & " + ( metaTemp.getReactionSet().size() - countReversibleReactions)+ " irrev\n" +
					metaTemp.getEnzymeSet().size() + " enzymes");
			countReversibleReactions = countReversibleReactions + reverseReactions(irreversibleReactions, degReactionRatio).size();

			System.err.println(metaTemp.getCompoundSet().size() + " compounds\n"+
					metaTemp.getReactionSet().size() + " reactions : \n" +
					countReversibleReactions +" rev & " + ( metaTemp.getReactionSet().size() - countReversibleReactions)+ " irrev\n" +
					metaTemp.getEnzymeSet().size() + " enzymes");
			
			for (Reaction<String> r :irreversibleReactions)
			{
				metaTemp.updateReaction(r);
			}
			
			if (metaboliteCutOff>0)
			{
				outLog = new BufferedWriter(new FileWriter(outRep+ "modele.log", true));
				outLog.write("Filtering Metabolic Network:\nRemoving metabolites that are present in more than "+metaboliteCutOff+" reactions\n\n");
				System.err.println("\n\nFiltering Metabolic Network:\nRemoving metabolites that are present in more than "+metaboliteCutOff+" reactions");
				outLog.close();
				MetabolicNetworkUtils<String, Reaction<String>> metaUtil = new MetabolicNetworkUtils<String, Reaction<String>>();
				Map<String, Integer> cutMap = metaUtil.compoundsCount(metaTemp);
				Collection<String> cutSet = new HashSet<String>();
				for (Entry<String, Integer> entry : cutMap.entrySet())
				{
					if (entry.getValue()>metaboliteCutOff)
					{
						cutSet.add(entry.getKey());
					}
				}
				outLog = new BufferedWriter(new FileWriter(outRep+ "modele.log", true));
				outLog.write("Removed compounds\n"+cutSet+"\n");
				System.err.println("Removed compounds\n"+cutSet);
				outLog.close();
				meta = new ImplOfFilteredMetabolicNetworkWithEnzymes<String, Reaction<String>, Protein>(metaTemp,cutSet);

				countReversibleReactions = 0;
				for (Reaction<String> r : meta.getReactionSet())
				{
					if (r.getDirection().equals(Orientation.BOTH) || r.getDirection().equals(Orientation.UNDEFINED))
					{
						countReversibleReactions++;
					}
				}
				System.err.println(meta.getCompoundSet().size() + " compounds\n"+
						meta.getReactionSet().size() + " reactions : \n" +
						countReversibleReactions +" rev & " + ( meta.getReactionSet().size() - countReversibleReactions)+ " irrev\n" +
						meta.getEnzymeSet().size() + " enzymes");
			}
			else
			{
				meta = metaTemp;
			}

			outLog = new BufferedWriter(new FileWriter(outRep+ "modele.log", true));
			outLog.write("Distance Loading\n\n");
			System.err.println("\nDistance Loading");
			outLog.close();

			DistanceBetweenGenes<Gene<Protein>> dist = null;
			if (isMetricMatrix)
			{
				IODistanceMatrix matrix = IODistanceMatrix.load(metricFile);
				//TODO Aligner sequence de genes et position sur matrice distance

				dist = new DistanceCoexpression<Gene<Protein>,Protein>(genome, matrix.getMatrix(), idsToGenes(genome,matrix.getIDs()));
			}
			else{
				dist = new DistanceColocalisation<Gene<Protein>,Protein>(genome);
			}


			//chargement des donnees sur les composants
			String dblinks = "DBLINKS";
			String ligand = "LIGAND-CPD \"([A-Z][0-9]{5})\" ";
			String matured = "MODIFIED-FORM";
			Pattern recoLigand = Pattern.compile(ligand);
			Matcher m;


			//			//Pour histoire et evolutions 
			//			// chargement des donnees sur les proteines.
			//			proteins = proteinsIn.readFile();
			//			for (Entry<String, Map<String, Collection<String>>> entry : proteins.entrySet())
			//			{
			//
			//				// association de l'instance avec ses types
			//				if (entry.getValue().containsKey(instanceOf))
			//				{
			//					for (String type : entry.getValue().get(instanceOf))
			//					{
			//						associeStringtoString(typesInstances, type, entry.getKey());
			//					}
			//				}
			//				// association composant avec complexe.
			//				if (entry.getValue().containsKey(componentOf))
			//				{
			//					for (String cpd : entry.getValue().get(componentOf))
			//					{
			//						associeStringtoString(componentOfComplex, cpd, entry.getKey());
			//					}
			//				}
			//
			//				// association composant avec complexe.
			//				if (entry.getValue().containsKey(matured))
			//				{
			//					for (String cpd : entry.getValue().get(matured))
			//					{
			//						associeStringtoString(modifiedComponents, cpd, entry.getKey());
			//					}
			//				}
			//			}
			//System.err.println(metabolites2genes);


			outLog = new BufferedWriter(new FileWriter(outRep+ "modele.log", true));
			outLog.write("Integrated Model creation\n\n");
			System.err.println("\nIntegrated Model creation");
			outLog.close();

			GenomicModel<Gene<Protein>, String, Reaction<String>, Protein> model = 
					new GenomicModel<Gene<Protein>, String, Reaction<String>, Protein>(meta, genome, dist);
			
			countReversibleReactions = 0;
			for (Reaction<String> r : model.getReactionSet())
			{
				if (r.getDirection().equals(Orientation.BOTH) || r.getDirection().equals(Orientation.UNDEFINED))
				{
					countReversibleReactions++;
				}
			}
			
			System.err.println(model.getGeneSet().size() + " genes\n"
					+ model.getReactionSet().size() + " reactions : "
					+ countReversibleReactions +" rev & " + ( model.getReactionSet().size() - countReversibleReactions)+ " irrev\n" +
					+ model.getEnzymeSet().size() + " enzymes\n");
			outLog = new BufferedWriter(new FileWriter(outRep+ "modele.log", true));
			outLog.write("Graph of Integrated Model creation\n\n");
			System.err.println("\nGraph of Integrated Model creation");
			outLog.close();

			GraphGenomicModel<Gene<Protein>, String, Reaction<String>, Protein> modelGraph = new GraphGenomicModel<Gene<Protein>, String, Reaction<String>, Protein>(model);
			modelGraph.generateGraph();

			System.err.println(modelGraph.getGraph().vertexSet().size() + " vertices\n"
					+modelGraph.getGraph().edgeSet().size() + " arcs");

			//sortie des associations avec sommets par genes, reactions et metabolites.
			Map<String, Set<Integer>> genesAssoMap = new HashMap<String,Set<Integer>>();
			Map<String, Set<Integer>> reactionsAssoMap = new HashMap<String,Set<Integer>>();
			Map<String, Set<Integer>> metabolitesAssoMap = new HashMap<String,Set<Integer>>();


			for (Integer v : modelGraph.getGraph().vertexSet())
			{
				String g = modelGraph.getLabel(v).getFirst();
				Set<Integer> elem = genesAssoMap.get(g);
				if (elem == null)
				{
					elem = new HashSet<Integer>();
					genesAssoMap.put(g, elem);
				}
				elem.add(v);
				String r = modelGraph.getLabel(v).getSecond();
				elem = reactionsAssoMap.get(r);
				if (elem == null)
				{
					elem = new HashSet<Integer>();
					reactionsAssoMap.put(r, elem);
				}
				elem.add(v);
			}

			IOSimpleGraph.export(modelGraph.getGraph(),outRep+ "modele.txt");
			writeLabels(outRep+  "labels.txt",modelGraph);
			
			exportAsso(genesAssoMap,outRep+ "associationsG.txt");
			exportAsso(reactionsAssoMap, outRep+ "associationsR.txt");
			//exportAsso(metabolitesAssoMap, outRep+ "associationsM.txt");
			Profil modele_profile = new Profil();
			modele_profile.put("workspace", outRep);
			modele_profile.put("gint", outRep+"modele.txt");
			modele_profile.put("labels", outRep+  "labels.txt");
			modele_profile.put("geneAssociation", outRep+ "associationsG.txt");
			modele_profile.put("reactionAssociation", outRep+ "associationsR.txt");
			modele_profile.writeProfil(outRep+"modele.profil");

			IObioASP asp = new IObioASP();
			asp.export(model, outRep+"genome.txt", outRep+"metabolism.txt", outRep+"catalyze.txt");
				
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
	
	// return the set of modified reactions
	private static List<Reaction<String>> reverseReactions(List<Reaction<String>> reactions, float degradationRatio)
	{
		Collections.shuffle(reactions);
		int end = Math.round(degradationRatio*reactions.size());
		System.err.println(end);
		List<Reaction<String>> result  = reactions.subList(0, end);
		for (Reaction<String> r : result)
		{
			r.setOrientation(Orientation.UNDEFINED);
		}
		return result;
	}

	

	private static void exportAsso(Map<String, Set<Integer>> assoMap, String file) throws IOException
	{
		BufferedWriter out = new BufferedWriter(new FileWriter(file));
		for (Entry<String, Set<Integer>> entry : assoMap.entrySet())
		{
			out.write(entry.getKey() + "\t");
			for (Integer i : entry.getValue())
			{
				out.write(i + " ");
			}
			out.write("\n");
		}
		out.close();
	}


	public static class Compare<T> implements Comparator<T>
	{

		private Map<T, Integer> map;
		public Compare(Map<T, Integer> map)
		{
			this.map = map;
		}

		@Override
		public int compare(T o1, T o2) {
			// TODO Auto-generated method stub
			return map.get(o2).compareTo(map.get(o1));
		}

	}

	public static class CompareGene<T> implements Comparator<T>
	{

		private Map<String, Map<String, Collection<String>>> map;
		private Collection<T> genesException;
		private String rightPos = "RIGHT-END-POSITION";
		private String leftPos = "LEFT-END-POSITION";


		public CompareGene(Map<String, Map<String, Collection<String>>> map, Collection<T> genesException)
		{
			this.map = map;
			this.genesException = genesException;
		}

		@Override
		public int compare(T o1, T o2) {
			if (genesException.contains(o1) || genesException.contains(o2))
			{
				return 1;
			}
			int result = Integer.parseInt(map.get(o1).get(leftPos).iterator().next().toString()) - Integer.parseInt(map.get(o2).get(leftPos).iterator().next().toString());
			if (result == 0)
			{
				result = Integer.parseInt(map.get(o1).get(rightPos).iterator().next().toString()) - Integer.parseInt(map.get(o2).get(rightPos).iterator().next().toString());
			}
			return result;
		}

	}

	//cree un genome ordonne
	public static SortedSet<String> createOrderedGenome(Map<String, Map<String, Collection<String>>> genes, Collection<String> genesException)
	{
		SortedSet<String> genome = new TreeSet<String>(new CompareGene<String>(genes, genesException));
		genome.addAll(genes.keySet());
		return genome;
	}


	//distance de colocalisation
	public static double distanceGenes(SortedSet<String> genome, Collection<String> genesException, String g1, String g2)
	{
		int result = 0;
		if (genesException.contains(g1) || genesException.contains(g2))
		{
			return Double.POSITIVE_INFINITY;
		}
		if (genome.tailSet(g1).contains(g2))
		{
			result = genome.subSet(g1, g2).size();
			if(result*2 > genome.size())
			{
				result = genome.size() - result;
			}
		}
		else
		{
			result = genome.subSet(g2, g1).size();
			if(result*2 > genome.size())
			{
				result = genome.size() - result;
			}
		}
		return (double)result;
	}


	//associe instance a type dans map. Ajoute type dans map si besoin.
	public static void associeStringtoString(Map<String, Collection<String>> map, String key, String instance)
	{
		Collection<String> col;
		if ((col = map.get(key)) == null)
		{
			col = new HashSet<String>();
			map.put(key, col);
		}
		col.add(instance);
	}

	//recherche instances de types dans instancesMap ainsi que les instances des types derives. Si rien alors retourner le type lui meme
	public static Collection<String> chercheInstances(Map<String, Collection<String>> typesMap, Map<String, Collection<String>> instancesMap, String type)
	{
		Collection<String> result = new HashSet<String>();
		List<String> aFaire = new LinkedList<String>();
		aFaire.add(type);
		while (!aFaire.isEmpty())
		{
			String elem = aFaire.remove(0);
			if (instancesMap.containsKey(elem))
			{
				//System.err.println(instancesMap.get(elem));
				result.addAll(instancesMap.get(elem));
			}
			if(typesMap.containsKey(elem))
			{
				aFaire.addAll(typesMap.get(elem));					

			}
		}
		if(result.isEmpty())
		{
			result.add(type);
		}
		//System.err.println("\t"+result);
		return result;
	}

	//graphe des complexes proteiques
	public static DefaultDirectedGraph<String, DefaultEdge> generateGraphComplexes(Map<String, Collection<String>> complexesMap, boolean direction)
	{
		DefaultDirectedGraph<String, DefaultEdge> graphComplexes = new DefaultDirectedGraph<String, DefaultEdge>(DefaultEdge.class);
		for (Entry<String, Collection<String>> entry : complexesMap.entrySet())
		{
			if (!graphComplexes.containsVertex(entry.getKey()))
			{
				graphComplexes.addVertex(entry.getKey());
			}
			for (String t : entry.getValue())
			{
				if (!graphComplexes.containsVertex(t))
				{
					graphComplexes.addVertex(t);
				}
				if (direction)
				{
					graphComplexes.addEdge(entry.getKey(), t);
				}
				else
				{
					graphComplexes.addEdge(t, entry.getKey());
				}
			}
		}
		return graphComplexes;
	}


	//equivalence KEGG
	public static Set<String> getKeggElements(String fileIn, String regExp) throws IOException
	{
		Set<String> result = new HashSet<String>();
		BufferedReader in = new BufferedReader(new FileReader(fileIn));
		String ch;
		Pattern reco = Pattern.compile(regExp);
		Matcher m;
		while((ch = in.readLine()) != null)
		{
			m = reco.matcher(ch);
			while (m.find())
			{
				result.add(new String(m.group(1)));
			}

		}
		in.close();
		return result;
	}

	//sommet de g accessibles à partir de s
	public static Collection<LinkedList<String>> accessible(DirectedGraph<String, DefaultEdge> g, String s)
	{
		Collection<LinkedList<String>> result = new HashSet<LinkedList<String>>();
		Set<String> pruned = new HashSet<String>();
		LinkedList<String> temp = new LinkedList<String>();
		temp.add(s);
		while (!temp.isEmpty())
		{
			if (!pruned.contains(temp.getFirst()))
			{
				LinkedList<String> l = new LinkedList<String>();
				l.add(temp.getFirst());
				result.add(l);
				pruned.add(temp.getFirst());
				for (DefaultEdge e : g.outgoingEdgesOf(temp.getFirst()))
				{
					//temp.add(g.getEdgeSource(e));
					temp.add(g.getEdgeTarget(e));
				}
			}
			temp.removeFirst();
		}
		pruned.clear();
		return result;
	}

	public static Collection<LinkedList<String>> ensembleDesChemins(UndirectedGraph<String, DefaultEdge> g, String s)
	{
		Collection<LinkedList<String>> result = ensembleDesChemins(g, s, new HashSet<String>());
		if (result.iterator().next().isEmpty())
		{
			result.clear();
		}
		return result;
	}


	private static Collection<LinkedList<String>> ensembleDesChemins(UndirectedGraph<String, DefaultEdge> g, String s, Set<String> pruned)
	{
		Collection<LinkedList<String>> result = new HashSet<LinkedList<String>>();
		Collection<LinkedList<String>> getResult;
		boolean empty = true;
		for (DefaultEdge e : g.edgesOf(s))
		{
			String t = g.getEdgeSource(e);
			if (t == s)
			{
				t = g.getEdgeTarget(e);
			}
			if (! pruned.contains(t))
			{
				empty = false;
				pruned.add(t);
				getResult = ensembleDesChemins(g, t, pruned);
				for (LinkedList<String> ch : getResult)
				{
					ch.addFirst(s);
				}
				result.addAll(getResult);
				pruned.remove(t);
			}
		}
		if (empty)
		{
			result.add(new LinkedList<String>());
		}
		return result;
	}

	public static List<Gene<Protein>> idsToGenes(Genome<Gene<Protein>, Protein> genome,List<String> ids)
	{
		List<Gene<Protein>> result = new ArrayList<Gene<Protein>>();
		for (String id : ids)
		{
			result.add(genome.getGene(id));
		}
		return result;
	}

	public static void writeLabels(String fileOut, GraphGenomicModel<Gene<Protein>, String, Reaction<String>, Protein> graph)
	{
		Writer out;
		try {
			out = new BufferedWriter(new FileWriter(fileOut));
			for (int i=0; i<graph.getGraph().vertexSet().size();i++)
			{
				out.write(i+"\t"+graph.getLabel(i)+"\n");
			}
			out.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}
